#include <algorithm>
#include <gmThread.h>
#include "PlayerList.h"

///GM Bindings
gmType GMPlayerList::m_userType = GM_NULL;

int GM_CDECL GMPlayerList::GMFindByName(gmThread *a_thread)
{
    if(a_thread->GetNumParams() >= 1)
    {
        GMPlayerList* thisObject = static_cast<GMPlayerList*>(a_thread->GetThis()->GetUserSafe(GMPlayerList::GetType()));

        if(thisObject)
        {
            std::string name = a_thread->ParamString(0, "");
            GMPlayer* player = thisObject->FindByName(name);

            if(player)
                a_thread->PushUser(player->GetUserObject());
            else a_thread->PushNull();

            return GM_OK;
        }
    }
    return GM_EXCEPTION;
}

int GM_CDECL GMPlayerList::GMFindByID(gmThread *a_thread)
{
    if(a_thread->GetNumParams() >= 1)
    {
        GMPlayerList* thisObject = static_cast<GMPlayerList*>(a_thread->GetThis()->GetUserSafe(GMPlayerList::GetType()));

        if(thisObject)
        {
            int playerID = a_thread->ParamInt(0);
            GMPlayer* player = thisObject->FindByID(playerID);

            if(player)
                a_thread->PushUser(player->GetUserObject());
            else a_thread->PushNull();

            return GM_OK;
        }
    }
    return GM_EXCEPTION;
}


void GM_CDECL GMPlayerList::GMOPIndexGet(gmThread * a_thread, gmVariable * a_operands)
{
    GMPlayerList* thisObject = static_cast<GMPlayerList*>(a_operands[0].GetUserSafe(GMPlayerList::GetType()));

    if(thisObject)
    {
        size_t index = a_operands[1].GetIntSafe();
        GMPlayer* player = thisObject->GetAt(index);

        if(player)
            a_operands[0] = gmVariable(player->GetUserObject());
        else a_operands[0].Nullify();
    } else a_operands[0].Nullify();
}

void GMPlayerList::Register(gmMachine* machine)
{
    m_userType = machine->CreateUserType("PlayerList");
    machine->RegisterTypeLibraryFunction(m_userType, "FindByName", GMFindByName, NULL);
    machine->RegisterTypeLibraryFunction(m_userType, "FindByID", GMFindByID, NULL);
    machine->RegisterTypeOperator(m_userType, O_GETIND, NULL, GMOPIndexGet);
}


void PlayerList::AddPlayer(int playerID, GMPlayer* player)
{
    m_playerIDs[playerID] = player;

    if(std::find(m_playerList.begin(), m_playerList.end(), player) == m_playerList.end())
        m_playerList.push_back(player);
}

void PlayerList::RemovePlayer(int playerID)
{
    std::map<int, GMPlayer*>::iterator it = m_playerIDs.find(playerID);

    if(it != m_playerIDs.end())
    {
        for(std::vector<GMPlayer*>::iterator it2 = m_playerList.begin(); it2 != m_playerList.end();)
        {
            if(*it2 == it->second)
            {
                m_playerList.erase(it2);
                break;
            } else ++it2;
        }
        m_playerIDs.erase(it);
    }
}

GMPlayer* PlayerList::FindByName(const std::string& name)
{
    for(size_t i = 0; i < PlayerCount(); ++i)
    {
        GMPlayer* player = GetAt(i);

        if(name == player->GetProperty(PLAYER_PROP_ACCOUNT).GetCStringSafe())
            return player;
    }
    return NULL;
}

GMPlayer* PlayerList::FindByID(int id)
{
    std::map<int, GMPlayer*>::iterator it = m_playerIDs.find(id);
    if(it != m_playerIDs.end())
        return it->second;
    return NULL;
}

GMPlayer* PlayerList::GetAt(size_t index)
{
    if(index < m_playerList.size())
        return m_playerList[index];
    return NULL;
}

